package com.atguigu.gmall.payment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.enums.model.OrderStatus;
import com.atguigu.gmall.enums.model.PaymentStatus;
import com.atguigu.gmall.enums.model.PaymentType;
import com.atguigu.gmall.order.client.OrderFeignClient;
import com.atguigu.gmall.order.model.OrderInfo;
import com.atguigu.gmall.payment.config.AlipayConfig;
import com.atguigu.gmall.payment.model.PaymentInfo;
import com.atguigu.gmall.payment.service.AlipayService;
import com.atguigu.gmall.payment.service.PaymentInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: atguigu
 * @create: 2023-01-28 16:20
 */
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {

    @Autowired
    private OrderFeignClient orderFeignClient;

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private AlipayClient alipayClient;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 渲染支付宝支付页面；保存本地交易记录
     *
     * @param orderId 订单ID
     * @return
     */
    @Override
    public String createAlipayForm(Long orderId) {
        try {
            //1.远程调用订单微服务获取订单信息 判断订单状态
            Result<OrderInfo> result = orderFeignClient.getOrderInfo(orderId);
            OrderInfo orderInfo = result.getData();
            //2.保存本地交易记录
            if (orderId != null && OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus()) && OrderStatus.UNPAID.name().equals(orderInfo.getProcessStatus())) {
                paymentInfoService.savePaymentInfo(orderInfo, PaymentType.ALIPAY.name());
            }
            //3.调用支付宝-统一收单下单并支付页面接口
            //3.1 创建支付宝页面请求对象
            AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
            //3.2 设置相关请求参数
            //支付宝异步回调支付微服务通知支付结果--通知商户系统
            request.setNotifyUrl(AlipayConfig.notify_payment_url);
            //支付宝同步支付结果结果回调-通知用户
            request.setReturnUrl(AlipayConfig.return_payment_url);
            JSONObject bizContent = new JSONObject();
            //商家自定义订单编号
            bizContent.put("out_trade_no", orderInfo.getOutTradeNo());
            //订单金额
            bizContent.put("total_amount", "0.01");
            //商品描述
            bizContent.put("subject", orderInfo.getTradeBody());
            //支付宝端支付的有效期
            bizContent.put("timeout_express", "10m");
            bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
            request.setBizContent(bizContent.toString());
            //3.3调用支付宝生成页面接口
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
            if (response.isSuccess()) {
                //从响应结果中得到支付渲染页面的表单
                return response.getBody();
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info("统一收单下单并支付页面接口调用异常：{}", e);
        }
        return "";
    }


    /**
     * 支付宝支付结果异步回表
     * 1.验证信息真伪，避免出现假通知
     * 2.做好幂等性处理-从参数中获取支付宝端notify_id
     * 3.验证订单状态，验证价格-支付宝支付金额跟本地支付金额是否一致
     * 4.如果支付成功，修改本地交易记录中支付状态为：已支付
     * 5.返回结果给支付宝
     *
     * @param paramsMap 支付宝提交相关参数
     * @return success:商家系统收到通知  failure:异步通知失败，支付宝间隔再次通知（最大努力通知：24小时22分中通知8次）
     */
    @Override
    public String payResultNofity(Map<String, String> paramsMap) {
        //0.获取响应相关参数
        String notifyId = paramsMap.get("notify_id");//通知ID
        String outTradeNo = paramsMap.get("out_trade_no");//商家订单ID
        String tradeStatus = paramsMap.get("trade_status");//交易状态
        String totalAmount = paramsMap.get("total_amount");//订单金额
        try {
            //1.验证信息真伪，避免出现假通知
            boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名
            if (!signVerified) {
                log.error("支付回调验签：验证签名失败");
                return "failure";
            }

            //2.做好幂等性处理-从参数中获取支付宝端notify_id
            Boolean flag = redisTemplate.opsForValue().setIfAbsent("notify:" + notifyId, "", 1462, TimeUnit.MINUTES);
            if (!flag) {
                return "failure";
            }
            //3.验证价格-支付宝支付金额跟本地支付金额是否一致
            PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
            if (paymentInfo == null || !PaymentStatus.UNPAID.name().equals(paymentInfo.getPaymentStatus())) {
                return "failure";
            }
            if (paymentInfo.getTotalAmount().compareTo(new BigDecimal(totalAmount)) != 0) {
                return "failure";
            }
            if ("TRADE_SUCCESS".equals(tradeStatus)) {
                //4.如果支付成功，修改本地交易记录中支付状态为：已支付
                paymentInfoService.paySuccess(outTradeNo, PaymentType.ALIPAY.name(), paramsMap);
                //5.返回结果给支付宝
                return "success";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            redisTemplate.delete("notify:" + notifyId);
        }
        return "failure";
    }

    /**
     * 发起退款
     *
     * @param orderId
     * @return
     */
    @Override
    public boolean refund(Long orderId) {
        try {
            //1.根据订单ID 支付方式查询本地交易记录 判断状态
            LambdaQueryWrapper<PaymentInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(PaymentInfo::getOrderId, orderId);
            queryWrapper.eq(PaymentInfo::getPaymentType, PaymentType.ALIPAY.name());
            PaymentInfo paymentInfo = paymentInfoService.getOne(queryWrapper);
            if (paymentInfo != null && !PaymentStatus.UNPAID.name().equals(paymentInfo.getPaymentStatus())) {
                //2.调用支付宝退款接口完成退款
                AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
                JSONObject bizContent = new JSONObject();
                //bizContent.put("trade_no", paymentInfo.getTradeNo());
                bizContent.put("out_trade_no", paymentInfo.getOutTradeNo());
                bizContent.put("refund_amount", 0.01);
                bizContent.put("out_request_no", "HZ01RF001");
                bizContent.put("refund_reason", "不喜欢，双方协商一致退款！");

                request.setBizContent(bizContent.toString());
                AlipayTradeRefundResponse response = alipayClient.execute(request);
                if (response.isSuccess()) {
                    //修改本地交易记录表中状态：已关闭
                    paymentInfo.setPaymentStatus(PaymentStatus.CLOSED.name());
                    paymentInfoService.updateById(paymentInfo);
                    return true;
                } else {
                    log.error("【支付微服务】发起退款失败：订单ID：{}", orderId);
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("【支付微服务】发起退款失败：订单ID：{},异常信息：{}", orderId, e);
        }
        return false;
    }

    /**
     * 根据订单ID关闭支付宝交易记录
     *
     * @param orderId 订单ID
     * @return
     */
    @Override
    public Boolean closePay(Long orderId) {
        try {
            //1.查询本地支付表信息
            PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentType.ALIPAY.name());

            //2.调用支付宝接口关闭支付宝交易
            if (paymentInfo != null) {
                AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
                JSONObject bizContent = new JSONObject();
                bizContent.put("trade_no", paymentInfo.getTradeNo());
                bizContent.put("out_trade_no", paymentInfo.getOutTradeNo());
                request.setBizContent(bizContent.toString());
                AlipayTradeCloseResponse response = alipayClient.execute(request);
                if (response.isSuccess()) {
                    return true;
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 查看是否有交易记录状态
     *
     * @param orderId
     * @return false:已关闭  true:未关闭
     */
    @Override
    public boolean checkPayment(Long orderId) {
        try {
            //1.查询本地交易记录
            PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentType.ALIPAY.name());

            //2.调用支付宝接口完成检查
            if (paymentInfo != null) {
                AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
                JSONObject bizContent = new JSONObject();
                bizContent.put("out_trade_no", paymentInfo.getOutTradeNo());
                bizContent.put("trade_no", paymentInfo.getTradeNo());
                request.setBizContent(bizContent.toString());
                AlipayTradeQueryResponse response = alipayClient.execute(request);
                if (response.isSuccess()) {
                    if ("TRADE_CLOSED".equals(response.getTradeStatus())) {
                        return false;
                    }
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return true;
    }
}
